@typeparam TItem
@inherits BaseDataGridComponent
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Blazorise.Extensions
@* there are two CascadingValue because one is used only to define columns, and the other is to build rows based on those columns *@
@* This one is to build rows *@

<CascadingValue Value="@this" IsFixed>
    @if ( IsPagerVisible && ( PagerPosition == DataGridPagerPosition.Top || PagerPosition == DataGridPagerPosition.TopAndBottom ) )
    {
        @paginationFragment
    }
    <Form>
        @if ( PreventDefaultSubmitBehavior )
        {
            <Button Type="ButtonType.Submit" PreventDefaultOnSubmit Disabled Display="DisplayNone"></Button>
        }

        @if ( IsGroupableByColumn )
        {
            <_DataGridColumnDropZone TItem="TItem" Columns="@groupableColumns" ColumnRemoved="@RemoveGroupColumn" ColumnAdded="@AddGroupColumn" />
        }
        <Table @ref="@tableRef" ElementId="@ElementId" Class="@ClassNames" Style="@Style" Margin="@Margin" Padding="@Padding" Striped="@Striped" Bordered="@Bordered" Borderless="@Borderless" Hoverable="@Hoverable" Narrow="@Narrow" Responsive="@Responsive" Resizable="@Resizable" ResizeMode="@ResizeMode" FixedHeader="@(Virtualize || FixedHeader)" FixedColumns="@FixedColumns" FixedColumnsPositionSync="@FixedColumnsPositionSync" FixedHeaderTableHeight="@GetFixedTableHeaderHeight()" FixedHeaderTableMaxHeight="@GetFixedTableHeaderMaxHeight()" ResponsiveMode="@ResponsiveMode" @attributes="@Attributes">
            @if ( !string.IsNullOrEmpty( Caption ) )
            {
                <TableCaption Side="@CaptionSide">
                    @Caption
                </TableCaption>
            }
            <TableHeader ThemeContrast="HeaderThemeContrast">
                @if ( IsGroupHeaderCaptionsEnabled )
                {
                    <TableRow Class="@HeaderRowStyling?.Class" Style="@HeaderRowStyling?.Style" Background="@(HeaderRowStyling?.Background ?? Background.Default)" Color="@(HeaderRowStyling?.Color ?? Color.Default)">
                        @groupIndentationFragment

                        @foreach ( var headerGroup in DisplayableHeaderGroupColumns )
                        {
                            var column = headerGroup.col;

                            @if ( string.IsNullOrWhiteSpace( column.HeaderGroupCaption ) || ( column.ColumnType == DataGridColumnType.Command && IsCommandVisible ) )
                            {
                                <TableRowHeader />
                            }
                            else
                            {
                                <TableHeaderCell ColumnSpan="headerGroup.colSpan" Class="@column.BuildHeaderCellClass()" Style="@column.BuildHeaderCellStyle()" TextAlignment="@column.HeaderCellTextAlignment" TextTransform="@column.HeaderCellTextTransform" TextDecoration="@column.HeaderCellTextDecoration" TextWeight="@column.HeaderCellTextWeight" TextOverflow="@column.HeaderCellTextOverflow" TextSize="@column.HeaderCellTextSize" VerticalAlignment="@column.HeaderCellVerticalAlignment" Display="@column.HeaderCellDisplay" Background="@column.HeaderCellBackground" Flex="@column.HeaderCellFlex" Gap="@column.HeaderCellGap" FixedPosition="@column.FixedPosition" Width="@column.BuildCellFluentSizing()">
                                    @if ( HeaderGroupCaptionTemplate is null )
                                    {
                                        @column.HeaderGroupCaption
                                    }
                                    else
                                    {
                                        @HeaderGroupCaptionTemplate( new HeaderGroupContext( column.HeaderGroupCaption ) )
                                    }
                                </TableHeaderCell>
                            }
                        }
                    </TableRow>
                }
                @if ( ShowCaptions )
                {
                    <TableRow Class="@HeaderRowStyling?.Class" Style="@HeaderRowStyling?.Style" Background="@(HeaderRowStyling?.Background ?? Background.Default)" Color="@(HeaderRowStyling?.Color ?? Color.Default)">

                        @groupIndentationFragment

                        @foreach ( var column in DisplayableColumns )
                        {
                            @if ( column.ColumnType == DataGridColumnType.Command )
                            {
                                @if ( IsCommandVisible || ( EditMode == DataGridEditMode.Inline || EditMode == DataGridEditMode.Cell ) )
                                {
                                    <TableHeaderCell Class="@column.BuildHeaderCellClass()" Style="@column.BuildHeaderCellStyle()" TextAlignment="@column.HeaderCellTextAlignment" TextTransform="@column.HeaderCellTextTransform" TextDecoration="@column.HeaderCellTextDecoration" TextWeight="@column.HeaderCellTextWeight" TextOverflow="@column.HeaderCellTextOverflow" TextSize="@column.HeaderCellTextSize" VerticalAlignment="@column.HeaderCellVerticalAlignment" Display="@column.HeaderCellDisplay" Background="@column.HeaderCellBackground" Flex="@column.HeaderCellFlex" Gap="@column.HeaderCellGap" FixedPosition="@column.FixedPosition" Width="@column.BuildCellFluentSizing()">
                                        @if ( CanInsertNewItem && editState != DataGridEditState.New )
                                        {
                                            <_DataGridNewCommand TItem="TItem" New="@New" />
                                        }
                                        @if ( BatchEdit )
                                        {
                                            <_DataGridSaveBatchCommand TItem="TItem" SaveBatch="@SaveBatch" />
                                            <_DataGridCancelBatchCommand TItem="TItem" CancelBatch="@Cancel" />
                                        }
                                    </TableHeaderCell>
                                }
                            }
                            else if ( column.ColumnType == DataGridColumnType.MultiSelect )
                            {
                                @if ( MultiSelect )
                                {
                                    <TableHeaderCell Class="@column.BuildHeaderCellClass()" Style="@column.BuildHeaderCellStyle()" TextAlignment="@column.HeaderCellTextAlignment" TextTransform="@column.HeaderCellTextTransform" TextDecoration="@column.HeaderCellTextDecoration" TextWeight="@column.HeaderCellTextWeight" TextOverflow="@column.HeaderCellTextOverflow" TextSize="@column.HeaderCellTextSize" VerticalAlignment="@column.HeaderCellVerticalAlignment" Display="@column.HeaderCellDisplay" Background="@column.HeaderCellBackground" Flex="@column.HeaderCellFlex" Gap="@column.HeaderCellGap" FixedPosition="@column.FixedPosition" Width="@column.BuildCellFluentSizing()">
                                        <_DataGridMultiSelectAll TItem="TItem" IsIndeterminate="@IsMultiSelectAllIndeterminate" IsChecked="@IsMultiSelectAllChecked"></_DataGridMultiSelectAll>
                                    </TableHeaderCell>
                                }
                            }
                            else
                            {
                                <TableHeaderCell Draggable="@(( IsGroupableByColumn && column.Groupable ) || column.Reorderable)" DragStart="@(() => OnColumnDragStarted( column ))" DragEnter="@(() => OnColumnDragEnter( column ))" DragEnd="@OnColumnDragEnded" ondragover="event.preventDefault();" Drop="@(() => OnColumnDropped( column ))"Class="@column.BuildHeaderCellClass()" Style="@column.BuildHeaderCellStyle()" Cursor="@(Sortable && column.Sortable ? Cursor.Pointer : Cursor.Default)" Clicked="@(() => Sort( column ))" TextAlignment="@column.HeaderCellTextAlignment" TextTransform="@column.HeaderCellTextTransform" TextDecoration="@column.HeaderCellTextDecoration" TextWeight="@column.HeaderCellTextWeight" TextOverflow="@column.HeaderCellTextOverflow" TextSize="@column.HeaderCellTextSize" VerticalAlignment="@column.HeaderCellVerticalAlignment" Display="@column.HeaderCellDisplay" Background="@column.HeaderCellBackground" Flex="@column.HeaderCellFlex" Gap="@column.HeaderCellGap" FixedPosition="@column.FixedPosition" Width="@column.BuildCellFluentSizing()">
                                    <Div Display="Display.InlineFlex">
                                        @if ( IsGroupableByColumn && column.Groupable )
                                        {
                                            <Icon Name="@IconName.GripVertical" Margin="MarginIs1FromEnd" Style="cursor:move" />
                                        }
                                        @if ( column.ShowCaption )
                                        {
                                            @if ( column.CaptionTemplate != null )
                                            {
                                                @column.CaptionTemplate( column )
                                            }
                                            else
                                            {
                                                @column.Caption
                                            }
                                        }

                                        @if ( Sortable && column.Sortable )
                                        {
                                            @if ( column.SortDirectionTemplate != null )
                                            {
                                                @column.SortDirectionTemplate( column.CurrentSortDirection )
                                            }
                                            else
                                            {
                                                if ( column.CurrentSortDirection == SortDirection.Default && ShowDefaultSortIcon )
                                                {
                                                    <Icon Name="@IconName.Sort" />
                                                }
                                                else if ( column.CurrentSortDirection != SortDirection.Default )
                                                {
                                                    <Icon Name="@(column.CurrentSortDirection == SortDirection.Descending ? IconName.SortDown : IconName.SortUp)" />
                                                }
                                            }
                                        }

                                        @if ( Filterable && column.Filterable && ( ( column.FilterMode.HasValue && column.FilterMode == DataGridFilterMode.Menu ) || ( !column.FilterMode.HasValue && FilterMode == DataGridFilterMode.Menu ) ) )
                                        {
                                            <_DataGridMenuFilter Column="column" />
                                        }
                                    </Div>
                                </TableHeaderCell>
                            }
                        }
                    </TableRow>
                }
                @if ( Filterable && ( FilterMode == DataGridFilterMode.Default || DisplayableColumns.Any( x => x.FilterMode == DataGridFilterMode.Default ) ) )
                {
                    <TableRow Class="@FilterRowStyling?.Class" Style="@FilterRowStyling?.Style" Background="@(FilterRowStyling?.Background ?? Background.Default)" Color="@(FilterRowStyling?.Color ?? Color.Default)">

                        @groupIndentationFragment

                        @foreach ( var column in DisplayableColumns )
                        {
                            @if ( column.ColumnType == DataGridColumnType.MultiSelect )
                            {
                                @if ( MultiSelect )
                                {
                                    <TableHeaderCell Class="@column.FilterCellClass" Style="@column.BuildFilterCellStyle()" TextAlignment="@column.FilterCellTextAlignment" TextTransform="@column.FilterCellTextTransform" TextDecoration="@column.FilterCellTextDecoration" TextWeight="@column.FilterCellTextWeight" TextOverflow="@column.FilterCellTextOverflow" TextSize="@column.FilterCellTextSize" VerticalAlignment="@column.FilterCellVerticalAlignment" Display="@column.FilterCellDisplay" Background="@column.FilterCellBackground" Flex="@column.FilterCellFlex" Gap="@column.FilterCellGap" FixedPosition="@column.FixedPosition" Width="@column.BuildCellFluentSizing()">
                                        @if ( column.FilterTemplate != null && column.Filterable )
                                        {
                                            @(column.FilterTemplate( column.Filter ))
                                        }
                                    </TableHeaderCell>
                                }
                            }
                            else if ( !column.Filterable )
                            {
                                <TableHeaderCell Class="@column.FilterCellClass" Style="@column.BuildFilterCellStyle()" TextAlignment="@column.FilterCellTextAlignment" TextTransform="@column.FilterCellTextTransform" TextDecoration="@column.FilterCellTextDecoration" TextWeight="@column.FilterCellTextWeight" TextOverflow="@column.FilterCellTextOverflow" TextSize="@column.FilterCellTextSize" VerticalAlignment="@column.FilterCellVerticalAlignment" Display="@column.FilterCellDisplay" Background="@column.FilterCellBackground" Flex="@column.FilterCellFlex" Gap="@column.FilterCellGap" FixedPosition="@column.FixedPosition" Width="@column.BuildCellFluentSizing()"></TableHeaderCell>
                                continue;
                            }
                            else if ( column.ColumnType == DataGridColumnType.Command )
                            {
                                @if ( IsCommandVisible )
                                {
                                    // since Clear Filter is located in the command column it can be visible only when Edit is enabled
                                    <TableHeaderCell Class="@column.FilterCellClass" Style="@column.BuildFilterCellStyle()" TextAlignment="@column.FilterCellTextAlignment" TextTransform="@column.FilterCellTextTransform" TextDecoration="@column.FilterCellTextDecoration" TextWeight="@column.FilterCellTextWeight" TextOverflow="@column.FilterCellTextOverflow" TextSize="@column.FilterCellTextSize" VerticalAlignment="@column.FilterCellVerticalAlignment" Display="@column.FilterCellDisplay" Background="@column.FilterCellBackground" Flex="@column.FilterCellFlex" Gap="@column.FilterCellGap" FixedPosition="@column.FixedPosition" Width="@column.BuildCellFluentSizing()">
                                        <_DataGridClearFilterCommand TItem="TItem" />
                                    </TableHeaderCell>
                                }
                            }
                            else if ( ( column.FilterMode.HasValue && column.FilterMode == DataGridFilterMode.Default ) || ( !column.FilterMode.HasValue && FilterMode == DataGridFilterMode.Default ) )
                            {

                                <TableHeaderCell Class="@column.FilterCellClass" Style="@column.BuildFilterCellStyle()" TextAlignment="@column.FilterCellTextAlignment" TextTransform="@column.FilterCellTextTransform" TextDecoration="@column.FilterCellTextDecoration" TextWeight="@column.FilterCellTextWeight" TextOverflow="@column.FilterCellTextOverflow" TextSize="@column.FilterCellTextSize" VerticalAlignment="@column.FilterCellVerticalAlignment" Display="@column.FilterCellDisplay" Background="@column.FilterCellBackground" Flex="@column.FilterCellFlex" Gap="@column.FilterCellGap" FixedPosition="@column.FixedPosition" Width="@column.BuildCellFluentSizing()">
                                    @if ( column.FilterTemplate != null )
                                    {
                                        @(column.FilterTemplate( column.Filter ))
                                    }
                                    else
                                    {
                                        <_DataGridCellFilter Column="column" OnFilterChanged="@(( newValue ) => OnFilterChanged( column, newValue ))" />
                                    }
                                </TableHeaderCell>
                            }
                            else
                            {
                                <TableHeaderCell Class="@column.FilterCellClass" Style="@column.BuildFilterCellStyle()" TextAlignment="@column.FilterCellTextAlignment" TextTransform="@column.FilterCellTextTransform" TextDecoration="@column.FilterCellTextDecoration" TextWeight="@column.FilterCellTextWeight" TextOverflow="@column.FilterCellTextOverflow" TextSize="@column.FilterCellTextSize" VerticalAlignment="@column.FilterCellVerticalAlignment" Display="@column.FilterCellDisplay" Background="@column.FilterCellBackground" Flex="@column.FilterCellFlex" Gap="@column.FilterCellGap" FixedPosition="@column.FixedPosition" Width="@column.BuildCellFluentSizing()"></TableHeaderCell>
                            }
                        }
                    </TableRow>
                }
                @if ( HasAggregates && !Virtualize && ShowAggregatesOnTop )
                {
                    @aggregateRowFragment
                }
            </TableHeader>
            <TableBody>
                @if ( IsNewItemInGrid )
                {
                    <_DataGridRowEdit @ref=dataGridRowEditRef TItem="TItem" Item="@editItem" ValidationItem="@validationItem" Columns="@Columns" CellValues="@editItemCellValues" EditMode="@EditMode" />
                }
                @if ( IsDisplayDataVisible )
                {
                    @if ( VirtualizeManualReadMode )
                    {
                        <Virtualize @ref="virtualizeRef" TItem="TItem" Context="item" ItemsProvider="VirtualizeItemsProviderHandler" OverscanCount="@(VirtualizeOptions?.OverscanCount ?? 10)">
                            <ChildContent>
                                @rowFragment( item )
                            </ChildContent>
                            <Placeholder>
                                <_DataGridFullColumnSpanRow TItem="TItem" Columns="@Columns">
                                    &nbsp;@LoadingTemplate
                                </_DataGridFullColumnSpanRow>
                            </Placeholder>
                        </Virtualize>
                    }
                    else if ( Virtualize )
                    {
                        <Virtualize @ref="virtualizeRef" TItem="TItem" Context="item" Items="@DisplayData.ToList()" OverscanCount="@(VirtualizeOptions?.OverscanCount ?? 10)">
                            <ChildContent>
                                @rowFragment( item )
                            </ChildContent>
                            <Placeholder>
                                <_DataGridFullColumnSpanRow TItem="TItem" Columns="@Columns">
                                    &nbsp;@LoadingTemplate
                                </_DataGridFullColumnSpanRow>
                            </Placeholder>
                        </Virtualize>
                    }
                    else
                    {
                        @if ( IsGroupEnabled )
                        {
                            @groupFragment( (0, DisplayGroupedData) )
                        }
                        else
                        {

                            @foreach ( var item in DisplayData )
                            {
                                @rowFragment( item )
                            }
                        }
                    }
                }
                @if ( IsEmptyTemplateVisible && !IsEmptyFilterTemplateVisible )
                {
                    <_DataGridFullColumnSpanRow TItem="TItem" Columns="@Columns">
                        @EmptyTemplate
                    </_DataGridFullColumnSpanRow>
                }
                @if ( IsEmptyFilterTemplateVisible && !IsEmptyTemplateVisible )
                {
                    <_DataGridFullColumnSpanRow TItem="TItem" Columns="@Columns">
                        @EmptyFilterTemplate
                    </_DataGridFullColumnSpanRow>
                }
                @if ( IsLoadingTemplateVisible )
                {
                    <_DataGridFullColumnSpanRow TItem="TItem" Columns="@Columns" RenderUpdates>
                        @LoadingTemplate

                    </_DataGridFullColumnSpanRow>
                }
            </TableBody>
            @if ( HasAggregates && !Virtualize && ShowAggregatesOnBottom )
            {
                <TableFooter>
                    @aggregateRowFragment
                </TableFooter>
            }
        </Table>
    </Form>
    @if ( IsPagerVisible && ( PagerPosition == DataGridPagerPosition.Bottom || PagerPosition == DataGridPagerPosition.TopAndBottom ) )
    {
        @paginationFragment
    }
    @if ( PopupVisible )
    {
        <_DataGridModal @ref=dataGridModalRef
                        TItem="TItem"
                        TitleTemplate="@PopupTitleTemplate"
                        EditItem="@editItem"
                        ValidationItem="@validationItem"
                        EditItemCellValues="@editItemCellValues"
                        Columns="@Columns"
                        PopupVisible="@PopupVisible"
                        PopupClosing="@PopupClosing"
                        PopupSize="@PopupSize"
                        EditState="@editState" />
    }
</CascadingValue>
@* This one is to hold information about columns *@
<CascadingValue Value="@this" IsFixed>
    @DataGridAggregates
    @DataGridColumns
    @ChildContent
</CascadingValue>

@code {

    private RenderFragment paginationFragment => __builder =>
    {
        <_DataGridPagination TItem="TItem" PaginationContext="@PaginationContext" PaginationTemplates="@PaginationTemplates" OnPaginationItemClick="@(EventCallback.Factory.Create<string>( this, Paginate ))" SelectedRow="@SelectedRow" />
    };

    protected RenderFragment<TItem> rowFragment => item => __builder =>
    {
        if ( IsEditItemInGrid( item ) )
        {
            <_DataGridRowEdit @ref=dataGridRowEditRef TItem="TItem" Item="@editItem" ValidationItem="@validationItem" Columns="@Columns" CellValues="@editItemCellValues" EditMode="@EditMode" />
        }
        else
        {
            <_DataGridRow @key="@item" TItem="TItem" Item="@item" SelectedRows="SelectedRows" SelectedRow="SelectedRow" />
            if ( DetailRowTemplate != null && ( GetRowInfo( item )?.DetailRowVisible ?? false ) )
            {
                <_DataGridDetailRow TItem="TItem" Item="@item" Columns="@Columns">
                    @DetailRowTemplate( item )
                </_DataGridDetailRow>
            }
        }
    };

    protected RenderFragment groupFragment( (int iteration, IEnumerable<GroupContext<TItem>> groupedData) x ) => __builder =>
    {
        @foreach ( var group in x.groupedData )
        {
            <TableRowGroup @key="group.Key" Expanded="@group.Expanded" ExpandedChanged="@group.SetExpanded" IndentTableCells="x.iteration">
                <TitleTemplate>
                    @if ( group.GroupTemplate is null )
                    {
                        @group.Key
                    }
                    else
                    {
                        @group.GroupTemplate( group )
                    }
                </TitleTemplate>
                <ChildContent>
                    @{
                        if ( group.NestedGroup is null )
                        {
                            @foreach ( var item in group.Items )
                            {
                                @rowFragment( item )
                            }
                        }
                        else
                        {
                            @groupFragment( (x.iteration + 1, group.NestedGroup) )
                        }
                    }
                </ChildContent>
            </TableRowGroup>
        }
    };

    protected internal RenderFragment groupIndentationFragment => __builder =>
    {
        @if ( IsGroupEnabled )
        {
            var count = GroupableColumnsCount;
            if ( count > 1 )
            {
                for ( int i = 1; i < count; i++ )
                {
                    <TableRowHeader />
                }
            }
        }
    };

    protected RenderFragment aggregateRowFragment => __builder =>
    {
        <_DataGridAggregateRow TItem="TItem" Aggregates="@Aggregates" Columns="@DisplayableColumns" Class="@AggregateRowStyling?.Class" Style="@AggregateRowStyling?.Style" Background="@(AggregateRowStyling?.Background ?? Background.Default)" Color="@(AggregateRowStyling?.Color ?? Color.Default)" />
    };
}